#ifndef SQLExprParser_HEADER_H
#define SQLExprParser_HEADER_H


#include <string>
#include <vector>

#include "../ast/SQLCommentHint.h"
#include "../ast/SQLDataType.h"
#include "../ast/SQLDataTypeImpl.h"
#include "../ast/SQLExpr.h"
#include "../ast/SQLName.h"
#include "../ast/SQLObject.h"
#include "../ast/SQLOrderBy.h"
#include "../ast/SQLOrderingSpecification.h"
#include "../ast/SQLOver.h"
#include "../ast/expr/SQLAggregateExpr.h"
#include "../ast/expr/SQLAllColumnExpr.h"
#include "../ast/expr/SQLAllExpr.h"
#include "../ast/expr/SQLAnyExpr.h"
#include "../ast/expr/SQLBetweenExpr.h"
#include "../ast/expr/SQLBinaryOpExpr.h"
#include "../ast/expr/SQLBinaryOperator.h"
#include "../ast/expr/SQLCaseExpr.h"
#include "../ast/expr/SQLCaseExpr_Item.h"
#include "../ast/expr/SQLCastExpr.h"
#include "../ast/expr/SQLCharExpr.h"
#include "../ast/expr/SQLCurrentOfCursorExpr.h"
#include "../ast/expr/SQLDefaultExpr.h"
#include "../ast/expr/SQLExistsExpr.h"
#include "../ast/expr/SQLHexExpr.h"
#include "../ast/expr/SQLIdentifierExpr.h"
#include "../ast/expr/SQLInListExpr.h"
#include "../ast/expr/SQLInSubQueryExpr.h"
#include "../ast/expr/SQLIntegerExpr.h"
#include "../ast/expr/SQLListExpr.h"
#include "../ast/expr/SQLMethodInvokeExpr.h"
#include "../ast/expr/SQLNCharExpr.h"
#include "../ast/expr/SQLNotExpr.h"
#include "../ast/expr/SQLNullExpr.h"
#include "../ast/expr/SQLNumberExpr.h"
#include "../ast/expr/SQLPropertyExpr.h"
#include "../ast/expr/SQLQueryExpr.h"
#include "../ast/expr/SQLSomeExpr.h"
#include "../ast/expr/SQLUnaryExpr.h"
#include "../ast/expr/SQLUnaryOperator.h"
#include "../ast/expr/SQLVariantRefExpr.h"
#include "../ast/statement/SQLNotNullConstraint.h"
#include "../ast/statement/SQLAssignItem.h"
#include "../ast/statement/SQLCharacterDataType.h"
#include "../ast/statement/SQLCheck.h"
#include "../ast/statement/SQLColumnCheck.h"
#include "../ast/statement/SQLColumnDefinition.h"
#include "../ast/statement/SQLColumnPrimaryKey.h"
#include "../ast/statement/SQLColumnReference.h"
#include "../ast/statement/SQLColumnUniqueKey.h"
#include "../ast/statement/SQLConstraint.h"
#include "../ast/statement/SQLForeignKeyConstraint.h"
#include "../ast/statement/SQLForeignKeyImpl.h"
#include "../ast/statement/SQLPrimaryKey.h"
#include "../ast/statement/SQLPrimaryKeyImpl.h"
#include "../ast/statement/SQLSelect.h"
#include "../ast/statement/SQLSelectOrderByItem.h"
#include "../ast/statement/SQLUnique.h"

#include "SQLParser.h"
#include "SQLParserFeature.h"
#include "../../DbType.h"
#include "../../utils/StringUtils.h"
#include "../../utils/common_ptr.h"

class SQLSelectParser;
class SQLUpdateSetItem;
class SQLPartitionValue;

class SQLExprParser : virtual public SQLParser
{

private:
  static SQLParserFeature_list_ptr empty_list;
  SQLHint_list_ptr myHints;
  static std::shared_ptr<std::vector<string_ptr>> strings;
  static BOOL_ptr __init;
  static BOOL_ptr init();

public:
  typedef SQLParser super;
  // static string_ptr  AGGREGATE_FUNCTIONS[];
  static std::shared_ptr<std::vector<string_ptr>> AGGREGATE_FUNCTIONS;
  static std::shared_ptr<std::vector<long>> AGGREGATE_FUNCTIONS_CODES;

  SQLExprParser(string_ptr sql);
  SQLExprParser(Lexer_ptr lexer);
  SQLExprParser(Lexer_ptr lexer, DbType_ptr dbType);
  SQLExprParser(string_ptr sql, DbType_ptr dbType);
  SQLExprParser(string_ptr sql, DbType_ptr dbType, SQLParserFeature_list_ptr features);
  ~SQLExprParser();

  SQLExpr_ptr getExpr();
  SQLExpr_ptr expr();
  SQLExpr_ptr exprRest(SQLExpr_ptr expr);
  SQLExpr_ptr bitXor();
  SQLExpr_ptr bitXorRest(SQLExpr_ptr expr);
  SQLExpr_ptr multiplicative();
  SQLExpr_ptr multiplicativeRest(SQLExpr_ptr expr);
  virtual SQLExpr_ptr primary();
  virtual SQLSelectParser_ptr createSelectParser();
  virtual SQLExpr_ptr primaryRest(SQLExpr_ptr expr);
  SQLExpr_ptr groupComparisionRest(SQLExpr_ptr expr);

  void getNames(SQLName_list_ptr exprCol);
  void getNames(SQLName_list_ptr exprCol, SQLObject_ptr parent);
  void exprList(SQLExpr_list_ptr exprCol);
  void exprList(SQLExpr_list_ptr exprCol, SQLObject_ptr parent);
  SQLName_ptr getName();
  virtual SQLName_ptr nameRest(SQLName_ptr name);
  BOOL_ptr isAggreateFunction(string_ptr word);
  SQLOrderBy_ptr parseOrderBy();
  SQLSelectOrderByItem_ptr parseSelectOrderByItem();
  SQLExpr_ptr bitAnd();
  SQLExpr_ptr bitAndRest(SQLExpr_ptr expr);
  SQLExpr_ptr bitOr();
  SQLExpr_ptr bitOrRest(SQLExpr_ptr expr);
  SQLExpr_ptr equality();
  SQLExpr_ptr equalityRest(SQLExpr_ptr expr);
  SQLExpr_ptr inRest(SQLExpr_ptr expr);
  SQLExpr_ptr additive();
  SQLExpr_ptr additiveRest(SQLExpr_ptr expr);
  SQLExpr_ptr shift();
  SQLExpr_ptr shiftRest(SQLExpr_ptr expr);
  SQLExpr_ptr getAnd();
  SQLExpr_ptr andRest(SQLExpr_ptr expr);
  SQLExpr_ptr getOr();
  SQLExpr_ptr orRest(SQLExpr_ptr expr);
  SQLExpr_ptr relational();
  SQLExpr_ptr relationalRest(SQLExpr_ptr expr);
  SQLExpr_ptr notRationalRest(SQLExpr_ptr expr);
  void accept(Token token);
  virtual SQLColumnDefinition_ptr parseColumn();
  SQLColumnDefinition_ptr parseColumn(SQLObject_ptr parent);
  virtual SQLColumnDefinition_ptr parseColumnRest(SQLColumnDefinition_ptr column);
  SQLConstraint_ptr parsePrimaryKey();
  SQLUnique_ptr parseUnique();
  SQLAssignItem_ptr parseAssignItem();
  void parseAssignItem(SQLAssignItem_list_ptr outList, SQLObject_ptr parent);
  virtual SQLAssignItem_ptr parseAssignItem(BOOL_ptr variant, SQLObject_ptr parent);
  SQLCommentHint_list_ptr parseHints();

  // template <typename T, typename O>
  // void parseHints(std::shared_ptr<std::list<O>> hints)
  // {
  //   // if (*lexer->token() == Token::HINT)
  //   // {
  //   //   string_ptr  tmp = lexer->stringVal();
  //   //   hints.push_back(new SQLCommentHint(tmp));
  //   //   lexer->nextToken();
  //   // }
  //   while (*lexer->token() == Token::HINT)
  //   {
  //     string_ptr  text = lexer->stringVal();
  //     SQLCommentHint *hint;

  //     if (lexer->isEnabled(&SQLParserFeature::TDDLHint) &&
  //         (StringUtils::startWith(text, "+ TDDL") ||
  //          StringUtils::startWith(text, "+TDDL") ||
  //          StringUtils::startWith(text, "!TDDL") ||
  //          StringUtils::startWith(text, "TDDL")))
  //     {
  //       // hint = new TDDLHint(text);
  //     }
  //     else
  //     {
  //       hint = new SQLCommentHint(text);
  //     }

  //     if (lexer->commentCount > 0)
  //     {
  //       hint->addBeforeComment(lexer->comments);
  //     }

  //     hints->push_back(dynamic_cast<T>(hint));
  //     lexer->nextToken();
  //   }
  // }
  // template <typename T, typename O>
  // void parseHints(std::shared_ptr<std::list<std::shared_ptr<O>>> hints)
  // {
  //   // if (*lexer->token() == Token::HINT)
  //   // {
  //   //   string_ptr  tmp = lexer->stringVal();
  //   //   hints.push_back(new SQLCommentHint(tmp));
  //   //   lexer->nextToken();
  //   // }
  //   while (*lexer->token() == Token::HINT)
  //   {
  //     string_ptr  text = lexer->stringVal();
  //     SQLCommentHint *hint;

  //     if (lexer->isEnabled(&SQLParserFeature::TDDLHint) &&
  //         (StringUtils::startWith(text, "+ TDDL") ||
  //          StringUtils::startWith(text, "+TDDL") ||
  //          StringUtils::startWith(text, "!TDDL") ||
  //          StringUtils::startWith(text, "TDDL")))
  //     {
  //       // hint = new TDDLHint(text);
  //     }
  //     else
  //     {
  //       hint = new SQLCommentHint(text);
  //     }

  //     if (lexer->commentCount > 0)
  //     {
  //       hint->addBeforeComment(lexer->comments);
  //     }

  //     hints->push_back(std::dynamic_pointer_cast<T>(hint));
  //     lexer->nextToken();
  //   }
  // }

  void parseHints(SQLCommentHint_list_ptr hints);
  void parseHints(SQLHint_list_ptr hints);

  SQLConstraint_ptr parseConstaint();
  SQLCheck_ptr parseCheck();
  SQLForeignKeyConstraint_ptr parseForeignKey();
  SQLUpdateSetItem_ptr parseUpdateSetItem();
  SQLSelectItem_ptr parseSelectItem();
  SQLDataType_ptr parseDataType();
  SQLDataType_ptr parseDataType(BOOL_ptr restrict);
  void parseQueryPlanHint(SQLExpr_ptr expr);
  BOOL_ptr isEnabled(SQLParserFeature_ptr feature);
  SQLName_ptr name();
  void over(SQLOver_ptr over);
  SQLLimit_ptr parseLimit();
  void setAllowIdentifierMethod(BOOL_ptr allowIdentifierMethod);
  SQLCharExpr_ptr charExpr();
  int parseIntValue();
  void names(SQLName_list_ptr exprCol);
  void names(SQLName_list_ptr exprCol, SQLObject_ptr parent);
  void orderBy(SQLSelectOrderByItem_list_ptr items, SQLObject_ptr parent);
  SQLCommentHint_ptr parseHint();
  void parseIndex(SQLIndexDefinition_ptr indexDefinition);
  void parseIndexRest(SQLIndex_ptr idx);
  void parseIndexRest(SQLIndex_ptr idx, SQLObject_ptr parent);
  SQLIntegerExpr_ptr integerExpr();
  SQLPartitionValue_ptr parsePartitionValues();

  // protected:
  // string_ptr  *aggregateFunctions;
  std::shared_ptr<std::vector<string_ptr>> aggregateFunctions;
  std::shared_ptr<std::vector<long>> aggregateFunctionHashCodes;
  BOOL_ptr allowIdentifierMethod;

  virtual SQLExpr_ptr parseInterval();

  SQLExpr_ptr methodRest(SQLExpr_ptr expr, BOOL_ptr acceptLPAREN);
  SQLExpr_ptr methodRest(SQLExpr_ptr expr, string_ptr name, bool aggregate);

  SQLExpr_ptr dotRest(SQLExpr_ptr expr);

  SQLAggregateExpr_ptr parseAggregateExpr(string_ptr methodName);

  virtual SQLAggregateExpr_ptr parseAggregateExprRest(SQLAggregateExpr_ptr aggregateExpr);

  virtual SQLDataType_ptr parseDataTypeRest(SQLDataType_ptr dataType);

  BOOL_ptr isCharType(string_ptr dataTypeName);
  BOOL_ptr isCharType(long hash);

  SQLDataType_ptr parseCharTypeRest(SQLCharacterDataType_ptr charType);

  SQLColumnDefinition_ptr createColumnDefinition();

  SQLColumnCheck_ptr parseColumnCheck();

  SQLCheck_ptr createCheck();

  SQLForeignKeyConstraint_ptr createForeignKey();
  SQLExpr_ptr parseAny();
  SQLExpr_ptr parseSome();
  SQLExpr_ptr parseAll();
  virtual SQLExpr_ptr parseAliasExpr(string_ptr alias)
  {
    return SQLExpr_ptr(new SQLIdentifierExpr(alias));
  }
  void over(SQLAggregateExpr_ptr aggregateExpr);

  SQLExternalRecordFormat_ptr parseRowFormat();
  SQLOver_WindowingBound_ptr parseWindowingBound();
};
// typedef boost::shared_ptr<SQLExprParser> SQLExprParser_ptr;

#endif
